/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package javamailclient;

import java.awt.HeadlessException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.URLName;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import mymail.cryptography.signature.SignatureRSA;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import mymail.cryptography.symmetric.Cryptography;
import mymail.crypttwice.SymmetricThenRSA;

/**
 * 
 * @author Abigail
 */
public class MailUtilities {

	// <editor-fold defaultstate="collapsed" desc="private parameter">
	private String host;
	private String protocol;
	private String userName;
	private String pwd;
	// </editor-fold>
	// <editor-fold defaultstate="collapsed" desc="public parameter">
	public Session session = null;
	public Store store = null;
	public Folder folder = null; // current folder
	public Folder[] folders = null;

	// </editor-fold>
	// <editor-fold defaultstate="collapsed" desc="Encapsulate Feild">
	/**
	 * @return the host
	 */
	public String getHost() {
		return host;
	}

	/**
	 * @param host
	 *            the host to set
	 */
	public void setHost(String host) {
		this.host = host;
	}

	/**
	 * @return the protocol
	 */
	public String getProtocol() {
		return protocol;
	}

	/**
	 * @param protocol
	 *            the protocol to set
	 */
	public void setProtocol(String protocol) {
		this.protocol = protocol;
	}

	/**
	 * @return the userName
	 */
	public String getUserName() {
		return userName;
	}

	/**
	 * @param userName
	 *            the userName to set
	 */
	public void setUserName(String userName) {
		this.userName = userName;
	}

	/**
	 * @return the pwd
	 */
	public String getPwd() {
		return pwd;
	}

	/**
	 * @param pwd
	 *            the pwd to set
	 */
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	// </editor-fold>
	// <editor-fold defaultstate="collapsed" desc="Constructor">
	public MailUtilities() {
		// this.host = pop3Yahoo;//imapYahoo;//pop3Gmail;
		// this.protocol = "imaps";
		// this.userName = "abigail.nguyen22";//"clovearleaf.2308";
		// this.pwd = "8411497109";
	}

	public MailUtilities(String _host, String _protocol, String _userName,
			String _pwd) {
		this.host = _host;
		this.protocol = _protocol;
		this.userName = _userName;
		this.pwd = _pwd;
	}

	// </editor-fold>
	// use this
	public boolean connect() throws NoSuchProviderException, MessagingException {

		boolean isConnect = false;

		StringBuilder builder = new StringBuilder();
		builder.append(getProtocol()).append("://");
		builder.append(getUserName()).append(":");
		builder.append(getPwd()).append("@");
		builder.append(getHost());

		// get system property
		Properties props = System.getProperties();
		if (protocol.toLowerCase().equals("imaps")) {
			props.setProperty("mail.store.protocol", "imaps");
			// props.setProperty("mail.imaps.partialfetch", "false");
		}
		// create new session
		session = Session.getDefaultInstance(props);

		URLName url = new URLName(builder.toString());

		store = session.getStore(url);

		store.connect();

		isConnect = true;

		return isConnect;
	}

	public void openFolder(String folderName) throws MessagingException {
		if (!store.isConnected()) {
			store.connect();
		}
		folder = store.getDefaultFolder();

		folder = folder.getFolder(folderName);
		try {
			folder.open(Folder.READ_WRITE);
		} catch (MessagingException ex) {
			folder.open(Folder.READ_ONLY);
		}
		// return folder;
	}

	public Folder[] getFolders() throws MessagingException {
		if (!store.isConnected()) {
			store.connect();
		}
		Folder parent = store.getDefaultFolder();
		folders = parent.list();
		return folders;
	}

	public void close() throws MessagingException {
		store.close();
	}

	// <editor-fold defaultstate="collapsed" desc="Asymmetric">
	/**
	 * send mail with Asymmetric RSA Algorithm
	 * 
	 * @param receiverMail
	 * @param subject
	 * @param content
	 * @param attachments
	 * @throws MessagingException
	 * @throws Exception
	 */
	public void sendSymAndASym(String symAlgorithm, String key,
			String receiverMail, String subject, String content,
			List<String> attachments, boolean isSign)
			throws MessagingException, Exception {
		// Pass cho AES phải >= 4 kí tự
		// Pass cho DES vÃ  DESede = 8 kí tự
		// String passwordData = "12345678";
		// String algorithm = "DESede";

		Key privateKey = null;
		Key publicKey = null;

		// receiverMail = "anm.hcb.receiver201@gmail.com";

		Properties props = new Properties();
		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.starttls.enable", "true");
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.port", "587");

		Session session = Session.getInstance(props,
				new javax.mail.Authenticator() {

					protected PasswordAuthentication getPasswordAuthentication() {
						return new PasswordAuthentication(userName, pwd);
					}
				});

		SymmetricThenRSA asymAlgorithm = new SymmetricThenRSA();

		Message message = new MimeMessage(session);

		message.setFrom(new InternetAddress(userName));

		message.setRecipients(Message.RecipientType.TO,
				InternetAddress.parse(receiverMail));

		message.setSubject(subject);

		MimeBodyPart messagePart = new MimeBodyPart();

		String text = asymAlgorithm.Encrypt(key, content, symAlgorithm);

		String signPath = "";
		if (isSign) {
			signPath = chooseFolderToSaveKey("Bạn vui lòng chọn đường dẫn lưu chữ kí")
					+ ".sign";

			// Bat nhap duong dan chu ky
			// Ky
			SignatureRSA.signEncryptedData(text, signPath,
					(PrivateKey) asymAlgorithm.getPrivateKey(),
					(PublicKey) asymAlgorithm.getPublicKey());
		}
		messagePart.setText(text);

		// mã hóa file attach
		List<String> encryptedFileNames = new ArrayList<String>();
		for (String filename : attachments) {
			encryptedFileNames.add(asymAlgorithm.EncryptFile(filename, key,
					symAlgorithm));

			// đính kèm chữ kí
			if (isSign) {
				SignatureRSA.signEncryptedFile(filename, signPath,
						(PrivateKey) asymAlgorithm.getPrivateKey(),
						(PublicKey) asymAlgorithm.getPublicKey());
			}
		}
		// String filename = rsa.EncryptFile("D://attachment.txt");

		privateKey = asymAlgorithm.getPrivateKey();
		publicKey = asymAlgorithm.getPublicKey();

		/**
		 * chọn đường dẫn lưu private key
		 */
		String privateFileName = chooseFolderToSaveKey("Bạn vui lòng chọn thư mục để lưu private key");
		if (privateKey.equals("")) {
			showError("Bạn chưa chọn thư mục để lưu file");
			return;
		}
		// lưu private key
		FileOutputStream fos = new FileOutputStream(privateFileName
				+ ".private");

		fos.write(privateKey.getEncoded());
		fos.close();

		/**
		 * chọn đường dẫn lưu public key k add cai nay, add vao se k giai ma dc
		 */
		// publicFileName k có extension (.public)
		String publicFileName = chooseFolderToSaveKey("Bạn chọn thư mục để lưu public key");

		fos = new FileOutputStream(publicFileName + ".public");
		fos.write(publicKey.getEncoded());
		fos.close();

		/**
		 * nén file .private
		 */
		ZipFile zipFile = new ZipFile(privateFileName + ".zip");// directory.getCanonicalFile()+
																// "/generatedKeypairs/test.zip");

		ArrayList<File> filesToAdd = new ArrayList<File>();

		File pri = new File(privateFileName + ".private");// directory.getCanonicalFile()+
															// "/generatedKeypairs/test.private");

		filesToAdd.add(pri);

		ZipParameters parameters = new ZipParameters();
		parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);

		parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

		parameters.setEncryptFiles(true);

		parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);

		// yêu cầu Private Key
		String pwd4PrivateKey = JOptionPane
				.showInputDialog("Bạn vui lòng nhập password để lưu private key");
		parameters.setPassword(pwd4PrivateKey);

		zipFile.addFiles(filesToAdd, parameters);
		// System.out.println("Zipped Private key!");

		pri.delete();
		// System.out.println("Deleted Private key!");

		// Attach file

		MimeBodyPart attachmentPart = new MimeBodyPart();

		for (String fileName : encryptedFileNames) {

			FileDataSource fileDataSource = new FileDataSource(fileName) {

				@Override
				public String getContentType() {
					return "text/plain";
				}
			};

			attachmentPart.setDataHandler(new DataHandler(fileDataSource));

			int last = fileName.lastIndexOf("/");

			String name = fileName.substring(last + 1);

			attachmentPart.setFileName(name);
		}

		Multipart multipart = new MimeMultipart();
		multipart.addBodyPart(messagePart);

		if (attachments.size() > 0) {// (attachmentPart.getFileName() != null) {
			multipart.addBodyPart(attachmentPart);
		}

		message.setContent(multipart);

		Transport.send(message);
	}

	/**
	 * receive mail encrypted by Asymmetric RSA Algorithm
	 * 
	 * @parasendm msg
	 * @throws MessagingException
	 * @throws IOException
	 * @throws ZipException
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 * @throws Exception
	 */
	public MyClientMail receiveSymAnAsym(Message msg)
			throws MessagingException, IOException, ZipException,
			NoSuchAlgorithmException, InvalidKeySpecException, Exception {
		MyClientMail myMail = new MyClientMail();
		// get from, subject from msg
		myMail.getEnvelope(msg);

		SymmetricThenRSA asymAlgorithm = new SymmetricThenRSA();

		// <editor-fold defaultstate="collapsed"
		// desc="đọc private key ở file zip">
		// Đọc key

		File directory = new File(".");
		String privateKeyPath = openKeyFolder("Bạn vui lòng chọn đường dẫn private key (.zip)");
		if (privateKeyPath.equals("")) {
			// showError("Bạn chưa chọn đường dẫn");
			throw new Exception("Bạn chưa chọn đường dẫn chứa private key");// return
																			// null;
		}
		ZipFile zipFile = new ZipFile(privateKeyPath);
		// nếu file zip (chứa private key) bị mã hóa
		// thì yêu cầu người dùng nhập mật khẩu để giải mã file
		if (zipFile.isEncrypted()) {
			String pwd4PrivateKey = JOptionPane
					.showInputDialog("Bạn vui lòng nhập password để đọc private key ");
			zipFile.setPassword(pwd4PrivateKey);
		}

		String parent = getFolderName(privateKeyPath);
		zipFile.extractAll(parent);// directory.getCanonicalFile() +
									// "/generatedKeypairs/");

		String symAlgorithm = getSymAlgorithmName();

		String keySymAlgorithm = JOptionPane
				.showInputDialog("Bạn vui lòng nhập key của thuật toán mã hóa "
						+ symAlgorithm);

		String privateKeyFileName = privateKeyPath.replace(".zip", ".private");

		// </editor-fold>

		// Xet coi co muon xac nhan chu ky khong
		boolean isSign = isSign();
		String signPath = "";
		String publicPath = "";

		if (isSign) {
			signPath = openKeyFolder("Bạn vui lòng nhập đường dẫn file chữ ký (.sign)")
					+ ".sign";
			publicPath = openKeyFolder("Bạn vui lòng nhập đường dẫn public key (.public)")
					+ ".public";
		}

		if (Multipart.class.isInstance(msg.getContent())) {
			Multipart parts = (Multipart) msg.getContent();
			int i;
			for (i = 0; i < parts.getCount(); i++) {
				javax.mail.BodyPart p = parts.getBodyPart(i);
				if (p.getFileName() == null) {
					try {

						String content = (String) p.getContent();

						String decryptedMessage;

						// Receive mail
						// Xac nhan chu ky
						boolean result3 = true;

						if (isSign) {
							result3 = SignatureRSA.verify(content, signPath,
									publicPath);
						}

						if (result3) {
							// Hien du lieu ra man hinh
							// Giai ma
							// Chen code giai ma vao
							decryptedMessage = SymmetricThenRSA.Decrypt(
									keySymAlgorithm, content, symAlgorithm,
									privateKeyFileName);
							myMail.setTextPlainContent(decryptedMessage);
						} else {
							// Hien khung chu ky khong dung
							showError("Chữ ký không đúng !!!");
						}

					} catch (Exception ex) {
						myMail.setTextPlainContent(p.getContent().toString());
					}
				} else {
					// Xử lý các part không phải là text
					InputStream stream = p.getInputStream();

					directory = new File(".");

					String outputFilename = directory.getCanonicalPath()
							+ "/temp/"
							+ (new Date()).toLocaleString().replace(" ", "")
									.replace(":", "").replace(",", "") + "_"
							+ p.getFileName();
					String inputFilename = directory.getCanonicalPath()
							+ "/downloads/"
							+ (new Date()).toLocaleString().replace(" ", "")
									.replace(":", "").replace(",", "")
							+ "_RSA_" + "output.txt";

					File f = new File(outputFilename);
					f.createNewFile();

					OutputStream out = new FileOutputStream(outputFilename);
					byte buf[] = new byte[1024];
					int len;
					while ((len = stream.read(buf)) > 0) {
						out.write(buf, 0, len);
					}
					out.close();
					stream.close();

					// Receive mail
					// Xac nhan chu ky
					boolean result4 = true;

					if (isSign) {
						result4 = SignatureRSA.verifyFile(outputFilename,
								signPath, publicPath);
					}
					if (result4) {
						// Giai ma
						// Cho nguoi dung xu ly tap tin
						// Giải mã
						SymmetricThenRSA.DecryptFile(outputFilename,
								inputFilename, keySymAlgorithm, symAlgorithm,
								privateKeyFileName);

						MyAttachment myAttach = new MyAttachment();
						myAttach.setFileName(p.getFileName());
						myAttach.setContentType(p.getContentType());
						myAttach.setContent(p);
						myMail.attachments.add(myAttach);
					} else {
						// Hien khung chu ky khong dung
						showError("chữ kí không đúng");
					}

				}
			}
		} else {
			// Text
			String content = (String) msg.getContent();

			String decryptedMessage = "";

			// Receive mail
			// Xac nhan chu ky
			boolean result3 = true;
			if (isSign) {
				result3 = SignatureRSA.verify(content, signPath, publicPath);
			}
			if (result3) {
				// Hien du lieu ra man hinh
				// Giai ma
				// Chen code giai ma vao
				decryptedMessage = asymAlgorithm.Decrypt(keySymAlgorithm,
						content, symAlgorithm, privateKeyFileName);
				myMail.setTextPlainContent(decryptedMessage);
			} else {
				// Hien khung chu ky khong dung
				showError("chữ kí không đúng !!!");
			}

			myMail.setTextPlainContent(decryptedMessage);

		}
		return myMail;
	}

	// </editor-fold>
	// <editor-fold defaultstate="collapsed" desc="Symmetric">
	public void sendSym(String algorithm, String receiverMail, String subject,
			String content, List<String> attachments, String key, boolean isSign)
			throws MessagingException, Exception {
		// algorithm = "AES";
		// receiverMail = "anm.hcb.receiver201@gmail.com";

		Properties props = new Properties();
		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.starttls.enable", "true");
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.port", "587");

		Session session = Session.getInstance(props,
				new javax.mail.Authenticator() {

					protected PasswordAuthentication getPasswordAuthentication() {
						return new PasswordAuthentication(userName, pwd);
					}
				});

		// Cryptography crypto = new Cryptography();

		Message message = new MimeMessage(session);

		message.setFrom(new InternetAddress(userName));

		message.setRecipients(Message.RecipientType.TO,
				InternetAddress.parse(receiverMail));

		message.setSubject(subject);

		MimeBodyPart messagePart = new MimeBodyPart();

		String verifiedContent = Cryptography.Encrypt(key, content, algorithm);

		// 1. Ky du lieu chua ma hoa hoac duoc ma hoa bang Symmetric

		// Send mail
		// Xet xem co check la se ky mail nay khong
		String signPath = "";
		String publicPath = "";
		if (isSign) {
			// Bat nhap duong dan chu ky
			signPath = openKeyFolder("Bạn vui lòng nhập đường dẫn file chữ ký (.sign)")
					+ ".sign";
			// Bat nhap duong dan public key
			publicPath = openKeyFolder("Bạn vui lòng nhập đường dẫn public key (.public)")
					+ ".public";
			// Ham nay se luu chu ky va public key
			SignatureRSA.signNonEncryptedData(verifiedContent, signPath,
					publicPath);
		}
		messagePart.setText(verifiedContent);
		//
		// Set the email attachment file
		//

		// mã hóa file attach
		// String[] encryptedFileName = new String[attachments.length];
		List<String> encryptedFileNames = new ArrayList<String>();
		for (String fileName : attachments) {// (int k = 0; k <
			// attachments.length; k++) {
			// fileName="D://attachment.txt";
			String filename = Cryptography
					.EncryptFile(fileName, key, algorithm);

			// 2. Ky tap tin chua ma hoa hoac duoc ma hoa bang Symmetric
			if (isSign) {
				// Send mail
				// Ky
				// Ham nay se luu chu ky va public key
				SignatureRSA.signNonEncryptedFile(filename, signPath,
						publicPath);
			}
			encryptedFileNames.add(filename);
		}

		// attach file
		MimeBodyPart attachmentPart = new MimeBodyPart();

		for (String fileName : encryptedFileNames) {
			FileDataSource fileDataSource = new FileDataSource(fileName) {

				@Override
				public String getContentType() {
					return "text/plain";
				}
			};

			attachmentPart.setDataHandler(new DataHandler(fileDataSource));

			int last = fileName.lastIndexOf("/");

			String name = fileName.substring(last + 1);

			attachmentPart.setFileName(name);
		}

		Multipart multipart = new MimeMultipart();
		multipart.addBodyPart(messagePart);
		if (attachments.size() > 0) {
			multipart.addBodyPart(attachmentPart);
		}
		message.setContent(multipart);

		Transport.send(message);
	}

	public MyClientMail receiveSym(Message msg, String algorithm)
			throws IOException, MessagingException, Exception {
		MyClientMail myMail = new MyClientMail();
		myMail.getEnvelope(msg);

		// Hoi nguoi ta xem co xac nhan chu ky khong
		// Co thi yeu cau nhap duong dan
		boolean isSign = isSign();
		String signPath = "";
		String publicPath = "";
		if (isSign) {
			signPath = openKeyFolder("Bạn vui lòng nhập đường dẫn file chữ ký (.sign)")
					+ ".sign";
			publicPath = openKeyFolder("Bạn vui lòng nhập đường dẫn public key (.public)")
					+ ".public";
		}
		String passwordData = JOptionPane
				.showInputDialog("Bạn vui lòng nhập key mã hóa thuật toán "
						+ algorithm);
		if (Multipart.class.isInstance(msg.getContent())) {
			Multipart parts = (Multipart) msg.getContent();
			int i;
			for (i = 0; i < parts.getCount(); i++) {
				javax.mail.BodyPart p = parts.getBodyPart(i);

				if (p.getFileName() == null) {
					try {
						// Text

						String content = (String) p.getContent();

						String decryptedMessage;

						decryptedMessage = Cryptography.Decrypt(passwordData,
								content, algorithm);

						// Receive mail
						// Xac nhan chu ky
						boolean result1 = true;
						if (isSign) {
							result1 = SignatureRSA.verify(decryptedMessage,
									signPath, publicPath);
						}
						if (result1) {
							// Hien du lieu ra man hinh
							myMail.setContentType(p.getContentType());
							myMail.setTextPlainContent(decryptedMessage);
						} else {
							// Hien khung chu ky khong dung
							showError("chữ kí không đúng");
						}

					} catch (Exception ex) {
						myMail.setTextPlainContent((String) p.getContent());
					}
				} else {
					// Xử lý các part không phải là text
					InputStream stream = p.getInputStream();

					File directory = new File(".");

					String outputFilename = directory.getCanonicalPath()
							+ "/temp/"
							+ new Date().toLocaleString().replace(" ", "")
									.replace(":", "") + "_" + p.getFileName();
					String inputFilename = directory.getCanonicalPath()
							+ "/downloads/"
							+ new Date().toLocaleString().replace(" ", "")
									.replace(":", "") + "_" + algorithm + "_"
							+ "output.txt";

					File f = new File(outputFilename);
					f.createNewFile();

					OutputStream out = new FileOutputStream(outputFilename);
					byte buf[] = new byte[(int) p.getSize()];
					int len;
					while ((len = stream.read(buf)) > 0) {
						out.write(buf, 0, len);
					}
					out.close();
					//
					// byte[] decryptedData = new byte[p.getSize()];
					//
					// DataInputStream dis = new DataInputStream(stream);
					// int read = 0;
					// int numRead = 0;
					// while (read < decryptedData.length
					// && (numRead = dis.read(decryptedData, read,
					// decryptedData.length - read)) >= 0) {
					// read = read + numRead;
					// }
					// stream.close();

					// Receive mail
					// Xac nhan chu ky
					boolean result2 = true;
					if (isSign) {
						result2 = SignatureRSA.verifyFile(outputFilename,
								"duong dan chu ky", "duong dan public key");
					}
					if (result2) {
						// Cho nguoi dung xu ly tap tin
						Cryptography.DecryptFile(outputFilename, inputFilename,
								passwordData, algorithm);

						MyAttachment myAttach = new MyAttachment();
						myAttach.setFileName(p.getFileName());
						myAttach.setContentType(p.getContentType());
						myAttach.setContent(p);
						myMail.attachments.add(myAttach);
					} else {
						// Hien khung chu ky khong dung
						showError("chữ kí không đúng");
					}
					f.delete();
				}
			}
		} else {
			try {
				String content = (String) msg.getContent();

				String decryptedMessage;

				decryptedMessage = Cryptography.Decrypt(passwordData, content,
						algorithm);

				// Receive mail
				boolean result1 = true;
				if (isSign) {
					// Xac nhan chu ky
					result1 = SignatureRSA.verify(decryptedMessage, signPath,
							publicPath);
				}
				if (result1) {
					// Hien du lieu ra man hinh
					myMail.setContentType(msg.getContentType());
					myMail.setTextPlainContent(decryptedMessage);
				} else {
					// Hien khung chu ky khong dung
					showError("chữ kí không đúng");
				}

			} catch (Exception ex) {
				myMail.setTextPlainContent((String) msg.getContent());
				myMail.setContentType(msg.getContentType());
			}
		}
		return myMail;
	}

	// </editor-fold>

	// <editor-fold defaultstate="collapsed" desc="None">
	public void send(String receiverMail, String subject, String content,
			List<String> attachments, boolean isSign)
			throws MessagingException, Exception {
		Properties props = new Properties();
		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.starttls.enable", "true");
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.port", "587");

		Session session = Session.getInstance(props,
				new javax.mail.Authenticator() {

					protected PasswordAuthentication getPasswordAuthentication() {
						return new PasswordAuthentication(userName, pwd);
					}
				});

		Message message = new MimeMessage(session);

		message.setFrom(new InternetAddress(userName));

		message.setRecipients(Message.RecipientType.TO,
				InternetAddress.parse(receiverMail));

		message.setSubject(subject);

		MimeBodyPart messagePart = new MimeBodyPart();

		String signPath = "";
		String publicPath = "";
		if (isSign) {
			// Bat nhap duong dan chu ky
			signPath = openKeyFolder("Bạn vui lòng nhập đường dẫn file chữ ký (.sign)")
					+ ".sign";
			// Bat nhap duong dan public key
			publicPath = openKeyFolder("Bạn vui lòng nhập đường dẫn public key (.public)")
					+ ".public";
			// Ham nay se luu chu ky va public key
			SignatureRSA.signNonEncryptedData(content, signPath, publicPath);
		}

		messagePart.setText(content);

		// attach file
		MimeBodyPart attachmentPart = new MimeBodyPart();

		for (String fileName : attachments) {

			// Khoi bat nhap duong dan vi o tren nhap oi

			// Send mail
			// Ky
			// Ham nay se luu chu ky va public key
			if (isSign) {
				SignatureRSA.signNonEncryptedFile(fileName, signPath,
						publicPath);
			}
			FileDataSource fileDataSource = new FileDataSource(fileName) {

				@Override
				public String getContentType() {
					return "text/plain";
				}
			};

			attachmentPart.setDataHandler(new DataHandler(fileDataSource));

			int last = fileName.lastIndexOf("/");

			String name = fileName.substring(last + 1);

			attachmentPart.setFileName(name);
		}

		Multipart multipart = new MimeMultipart();

		multipart.addBodyPart(messagePart);
		if (attachments.size() > 0) {
			multipart.addBodyPart(attachmentPart);
		}
		message.setContent(multipart);
		Transport.send(message);
	}

	public MyClientMail receive(Message msg) throws MessagingException,
			IOException, Exception {
		MyClientMail myMail = new MyClientMail();
		myMail.getEnvelope(msg);

		// Hoi nguoi ta xem co xac nhan chu ky khong
		// Co thi bat nhap duong dan
		boolean isSign = isSign();
		String signPath = "";
		String publicPath = "";
		if (isSign) {
			signPath = openKeyFolder("Bạn vui lòng nhập đường dẫn file chữ ký (.sign)")
					+ ".sign";
			publicPath = openKeyFolder("Bạn vui lòng nhập đường dẫn public key (.public)")
					+ ".public";
		}
		if (Multipart.class.isInstance(msg.getContent())) {
			Multipart parts = (Multipart) msg.getContent();
			int i;
			for (i = 0; i < parts.getCount(); i++) {
				javax.mail.BodyPart p = parts.getBodyPart(i);

				if (p.getFileName() == null) {
					try {
						String content = (String) p.getContent();
						boolean result1 = true;
						if (isSign) {
							result1 = SignatureRSA.verify(content, signPath,
									publicPath);
						}
						if (result1) {
							// Hien du lieu ra man hinh
							myMail.setContentType(p.getContentType());
							myMail.setTextPlainContent(content);
						} else {
							// Hien khung chu ky khong dung
							showError("chữ kí không đúng");
						}

					} catch (Exception ex) {
						myMail.setContentType(p.getContentType());
						myMail.setTextPlainContent((String) p.getContent());
					}
				} else {
					// Xử lý các part không phải là tex
					// đây nè

					InputStream stream = p.getInputStream();

					File directory = new File(".");

					String outputFilename = directory.getCanonicalPath()
							+ "/temp/"
							+ new Date().toLocaleString().replace(" ", "")
									.replace(":", "") + "_" + p.getFileName();

					// Luu file tam de xac nhan chu ky
					File f = new File(outputFilename);
					f.createNewFile();

					OutputStream out = new FileOutputStream(outputFilename);
					byte buf[] = new byte[p.getSize()];
					int len;
					while ((len = stream.read(buf)) > 0) {
						out.write(buf, 0, len);
					}
					out.close();

					// Receive mail
					// Xac nhan chu ky

					// Bat nhap duong dan chu ky
					// Bat nhap duong dan public key
					boolean result2 = true;
					if (isSign) {
						result2 = SignatureRSA.verifyFile(outputFilename,
								signPath, publicPath);
					}
					if (result2) {
						// Cho nguoi dung xu ly tap tin
						MyAttachment myAttach = new MyAttachment();
						myAttach.setFileName(p.getFileName());
						myAttach.setContentType(p.getContentType());

						myAttach.setContent(p);
						myMail.attachments.add(myAttach);

					} else {
						// Hien khung chu ky khong dung <= Cai gi khong dung la
						// khong cho doc
						// Khong dung nen xoa file tam luon
						showError("chữ kí không đúng");
					}
					f.delete();
				}
			}
		} else {
			try {
				String content = (String) msg.getContent();
				boolean result1 = true;
				if (isSign) {
					result1 = SignatureRSA.verify(content, "duong dan chu ky",
							"duong dan public key");
				}
				if (result1) {
					// Hien du lieu ra man hinh
					myMail.setContentType(msg.getContentType());
					myMail.setTextPlainContent(content);
				} else {
					// Hien khung chu ky khong dung
					showError("chữ kí không đúng");
				}

			} catch (Exception ex) {
				myMail.setTextPlainContent((String) msg.getContent());
			}
		}
		return myMail;
	}

	// </editor-fold>

	// <editor-fold defaultstate="collapsed" desc="private function">
	public String getSymAlgorithmName() {
		Object[] symAlgoArray = new String[] { "AES", "DES", "3DES" };
		String symAlgorithm = (String) JOptionPane.showInputDialog(null,
				"Bạn vui lòng chọn thuật toán", "Select Algorithm",
				JOptionPane.QUESTION_MESSAGE, null, symAlgoArray,
				symAlgoArray[0]);
		if (symAlgorithm.equals("3DES")) {
			symAlgorithm = "DESede";
		}
		return symAlgorithm;
	}

	public int getCryptographyName() {
		Object[] symAlgoArray = new String[] { "None", "Symmetric",
				"Symmetric Then Asymmetric" };
		String crypto = (String) JOptionPane.showInputDialog(null,
				"Bạn vui lòng chọn phương thức mã hóa", "Select Cryptographic",
				JOptionPane.QUESTION_MESSAGE, null, symAlgoArray,
				symAlgoArray[0]);
		if (crypto.equals("None")) {
			return 0;
		}
		if (crypto.equals("Symmetric")) {
			return 1;
		}
		return 2;
	}

	private void showError(String message) {
		JOptionPane.showMessageDialog(null, message, "Error",
				JOptionPane.ERROR_MESSAGE);
	}

	private String chooseFolderToSaveKey(String msg) throws HeadlessException {
		String privateFileName = "";
		int choose = JOptionPane.showConfirmDialog(null, msg, "",
				JOptionPane.OK_CANCEL_OPTION);
		if (choose == JOptionPane.OK_OPTION) {
			JFileChooser fileChooser = new JFileChooser();
			int ok = fileChooser.showSaveDialog(null);
			if (ok == JFileChooser.APPROVE_OPTION) {
				privateFileName = fileChooser.getSelectedFile()
						.getAbsolutePath();// .getParent() + "/test.private";
			}
		}
		return privateFileName;
	}

	private String openKeyFolder(String msg) {
		String privateFileName = "";
		int choose = JOptionPane.showConfirmDialog(null, msg, "",
				JOptionPane.OK_CANCEL_OPTION);
		if (choose == JOptionPane.OK_OPTION) {
			JFileChooser fileChooser = new JFileChooser();
			// FileFilter filter1 = new
			// ExtensionFileFilter(".zip, .private, .public", new
			// String[]{"zip", "private","public"});
			// fileChooser.setFileFilter(filter1);
			int ok = fileChooser.showOpenDialog(null);
			if (ok == JFileChooser.APPROVE_OPTION) {
				privateFileName = fileChooser.getSelectedFile()
						.getAbsolutePath();// .getParent() + "/test.private";
			}
		}
		return privateFileName;
	}

	private boolean isSign() {
		int choose = JOptionPane.showConfirmDialog(null,
				"Bạn có muốn xác nhận chữ kí không???", "",
				JOptionPane.OK_CANCEL_OPTION);
		if (choose == JOptionPane.OK_OPTION) {
			return true;
		}
		return false;
	}

	private String getFolderName(String filePath) {
		filePath = filePath.replace("\\", "/");
		String[] seps = filePath.split("/");
		String folderName = filePath.replace(seps[seps.length - 1], "");
		return folderName;
	}

	// </editor-fold>

	// <editor-fold defaultstate="collapsed" desc="delete msg">

	@SuppressWarnings("deprecation")
	public boolean deleteOnClient(Message msg) throws Exception {
		String msgDetail = msg.getReceivedDate().toLocaleString()
				.replace(" ", "").replace(":", "").replace(",", "");

		File history = new File("./history/" + userName + "_deletedFile.txt");

		if (!history.exists()) {
			history.createNewFile();
		}

		FileWriter fstream = new FileWriter(history.getAbsolutePath(), true);
		BufferedWriter out = new BufferedWriter(fstream);
		out.write(msgDetail);
		out.newLine();
		out.close();

		return true;
	}

	public boolean deleteOnServer(Message msg) throws Exception {
		int mode = folder.getMode();
		if (folder.isOpen() && mode == Folder.READ_WRITE) {
			msg.setFlag(Flags.Flag.DELETED, true);
			folder.close(true);
			folder.open(mode);
		} else {
			return false;
		}
		return true;
	}

	public boolean delete(Message msg) throws Exception {
		int mode = folder.getMode();
		if (folder.isOpen() && mode == Folder.READ_WRITE) {
			deleteOnClient(msg);
			msg.setFlag(Flags.Flag.DELETED, true);
			folder.close(true);
			folder.open(mode);
		} else {
			return false;
		}
		return true;
	}

	@SuppressWarnings("deprecation")
	public boolean checkIfDeletedOnClient(Message msg) throws Exception {
		String msgDetail = msg.getReceivedDate().toLocaleString()
				.replace(" ", "").replace(":", "").replace(",", "");

		File history = new File("./history/" + userName + "_deletedFile.txt");

		if (history.exists()) {
			FileInputStream fstream = new FileInputStream(
					history.getAbsoluteFile());
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null) {
				if (msgDetail.equals(strLine)) {
					return true;
				}
			}
			in.close();
		}

		return false;
	}
	// </editor-fold>
}
